package com.skyolder.milkbee.web.rest.pub;

import java.net.URI;
import java.net.URISyntaxException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.codahale.metrics.annotation.Timed;
import com.skyolder.milkbee.domain.Card;
import com.skyolder.milkbee.domain.Comment;
import com.skyolder.milkbee.domain.Estate;
import com.skyolder.milkbee.domain.Leaguer;
import com.skyolder.milkbee.domain.Moderator;
import com.skyolder.milkbee.domain.User;
import com.skyolder.milkbee.dto.CardComment;
import com.skyolder.milkbee.dto.HomeCard;
import com.skyolder.milkbee.dto.SimpleResult;
import com.skyolder.milkbee.repository.EstateRepository;
import com.skyolder.milkbee.security.AuthoritiesConstants;
import com.skyolder.milkbee.security.SecurityUtils;
import com.skyolder.milkbee.service.CardService;
import com.skyolder.milkbee.service.CommentService;
import com.skyolder.milkbee.service.LeaguerService;
import com.skyolder.milkbee.service.ModeratorService;
import com.skyolder.milkbee.service.UserService;
import com.skyolder.milkbee.tool.StringUtil;
import com.skyolder.milkbee.web.rest.util.HeaderUtil;
import com.skyolder.milkbee.web.rest.util.PaginationUtil;

import io.swagger.annotations.ApiParam;

/**
 * REST controller for managing Card.
 */
@RestController("pubCardResource")
@RequestMapping("/api/pub")
public class CardResource {

	private final Logger log = LoggerFactory.getLogger(CardResource.class);

	@Inject
	private CardService cardService;
	@Inject
	private CommentService commentService;
	@Inject
	private UserService userService;
	@Inject
	private LeaguerService leaguerService;
	@Inject
	private ModeratorService moderatorService;

	@Inject
	private EstateRepository estateRepository;

	/**
	 * POST /cards : Create a new card.
	 *
	 * @param card
	 *            the card to create
	 * @return the ResponseEntity with status 201 (Created) and with body the
	 *         new card, or with status 400 (Bad Request) if the card has
	 *         already an ID
	 * @throws URISyntaxException
	 *             if the Location URI syntax is incorrect
	 */
	@PostMapping("/cards")
	@Timed
	public ResponseEntity<Card> createCard(@RequestBody Card card) throws URISyntaxException {
		log.debug("REST request to save Card : {}", card);
		if (card.getId() != null) {
			return ResponseEntity.badRequest()
					.headers(HeaderUtil.createFailureAlert("card", "idexists", "A new card cannot already have an ID"))
					.body(null);
		}
		card.setAccusation(0L);
		card.setAuthor(SecurityUtils.getCurrentUserLogin());
		card.setCommentCount(0L);
		card.setCreatedAt(ZonedDateTime.now());
		card.setModifiedAt(ZonedDateTime.now());
		card.setDownload(0L);
		card.setEssence(0);
		if(StringUtil.isBlank(card.getAttachment())){
			card.setCost(0L);
		}
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		ouser.ifPresent((user) -> {
			card.setUserId(user.getId());
			// card.setLeaguerId();
			Leaguer l = leaguerService.findByUser(user);
			l.setCardCount(l.getCardCount() + 1L);
			leaguerService.save(l);
			card.setLeaguerId(l.getId());
		});
		card.setLight(0L);
		card.setLook(0L);
		card.setRecommend(false);
		card.setRecommendTitle(card.getTitle());
		Card result = cardService.save(card);
		return ResponseEntity.created(new URI("/api/cards/" + result.getId()))
				.headers(HeaderUtil.createEntityCreationAlert("card", result.getId().toString())).body(result);
	}

	/**
	 * PUT /cards : Updates an existing card.
	 *
	 * @param card
	 *            the card to update
	 * @return the ResponseEntity with status 200 (OK) and with body the updated
	 *         card, or with status 400 (Bad Request) if the card is not valid,
	 *         or with status 500 (Internal Server Error) if the card couldnt be
	 *         updated
	 * @throws URISyntaxException
	 *             if the Location URI syntax is incorrect
	 */
	@PutMapping("/cards")
	@Timed
	public ResponseEntity<Card> updateCard(@RequestBody Card card) throws URISyntaxException {
		log.debug("REST request to update Card : {}", card);
		if (card.getId() == null) {
			return createCard(card);
		}
		Card result = cardService.save(card);
		return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert("card", card.getId().toString()))
				.body(result);
	}

	/**
	 * GET /cards : get all the cards.
	 *
	 * @param pageable
	 *            the pagination information
	 * @return the ResponseEntity with status 200 (OK) and the list of cards in
	 *         body
	 * @throws URISyntaxException
	 *             if there is an error to generate the pagination HTTP headers
	 */
	@GetMapping("/cards")
	@Timed
	public ResponseEntity<List<Card>> getAllCards(@ApiParam Pageable pageable) throws URISyntaxException {
		log.debug("REST request to get a page of Cards");
		Page<Card> page = cardService.findAll(pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/cards");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}

	@GetMapping("/modcard")
	@Timed
	public ResponseEntity<List<Card>> getAllAccusationCards(@ApiParam Pageable pageable) throws URISyntaxException {
		log.debug("REST request to get a page of Cards");
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		List<Moderator> moderators = moderatorService.findByUserId(user.getId());
		Page<Card> page = cardService.doQueryAccusationByModerator(moderators, pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/cards");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}

	@GetMapping("/applycard")
	@Timed
	public ResponseEntity<List<Card>> getAllApplyCards(@ApiParam Pageable pageable) throws URISyntaxException {
		log.debug("REST request to get a page of Cards");
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		List<Moderator> moderators = moderatorService.findByUserId(user.getId());
		Page<Card> page = cardService.doQueryApplyByModerator(moderators, pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/cards");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}

	/**
	 * GET /cards/:id : get the "id" card.
	 *
	 * @param id
	 *            the id of the card to retrieve
	 * @return the ResponseEntity with status 200 (OK) and with body the card,
	 *         or with status 404 (Not Found)
	 */
	@GetMapping("/cards/{id}")
	@Timed
	public ResponseEntity<Card> getCard(@PathVariable Long id) {
		log.debug("REST request to get Card : {}", id);
		Card card = cardService.findOne(id);
		return Optional.ofNullable(card).map(result -> new ResponseEntity<>(result, HttpStatus.OK))
				.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
	}

	/**
	 * DELETE /cards/:id : delete the "id" card.
	 *
	 * @param id
	 *            the id of the card to delete
	 * @return the ResponseEntity with status 200 (OK)
	 */
	@DeleteMapping("/cards/{id}")
	@Timed
	public ResponseEntity<Void> deleteCard(@PathVariable Long id) {
		log.debug("REST request to delete Card : {}", id);
		cardService.delete(id);
		return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("card", id.toString())).build();
	}

	@GetMapping("/card/category/{categoryId}")
	@Timed
	public ResponseEntity<List<Card>> getCardsByCartegory(@PathVariable Long categoryId, @ApiParam Pageable pageable)
			throws URISyntaxException {
		log.debug("REST request to get a page of Cards");
		Page<Card> page = cardService.findByCategoryId(categoryId, pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/category/");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}

	@GetMapping("/card/comments/{cardId}")
	@Timed
	public ResponseEntity<List<CardComment>> getCardAndComments(@PathVariable Long cardId, @ApiParam Pageable pageable)
			throws URISyntaxException {
		Card card = cardService.findOne(cardId);
		Page<CardComment> page = commentService.doQueryCardCommentsByCardId(cardId, pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/card/comments/");
		card.setLook(card.getLook() + 1L);
		cardService.save(card);
		List<CardComment> list = new ArrayList<CardComment>();
		CardComment c = new CardComment();
		c.setContent(card.getContent());
		c.setAuthor(card.getAuthor());
		c.setCreatedAt(card.getCreatedAt());
		c.setLight(card.getLight());
		c.setSeq(0L);
		c.setMain(true);
		c.setId(card.getId());
		c.setTitle(card.getTitle());
		c.setAttachment(card.getAttachment());
		c.setDownload(card.getDownload());
		c.setEssence(card.getEssence());
		Leaguer leaguer = leaguerService.findOne(card.getLeaguerId());
		if (leaguer != null) {
			c.setUserId(leaguer.getUserId());
			c.setMana(leaguer.getMana());
			c.setAuthentication(leaguer.isAuthentication());
			Estate estate = estateRepository.findByRank(leaguer.getEstateRank());
			c.setEstate(estate.getName());
			c.setAvatar(leaguer.getAvatar());
			c.setUnderwrite(leaguer.getUnderwrite());
		}
		
		list.add(c);
		List<CardComment> pg = page.getContent();
		if (pg != null) {
			for (CardComment cc : pg) {
				list.add(cc);
			}
		}

		return new ResponseEntity<>(list, headers, HttpStatus.OK);
	}

	@GetMapping("/card/recommends/{count}")
	@Timed
	public ResponseEntity<List<HomeCard>> getCardRecommends(@PathVariable Integer count) throws URISyntaxException {
		List<HomeCard> list = cardService.doQueryCardRecommends(count);
		return new ResponseEntity<>(list, HttpStatus.OK);
	}

	@GetMapping("/card/essences/{count}")
	@Timed
	public ResponseEntity<List<HomeCard>> getCardEssences(@PathVariable Integer count) throws URISyntaxException {
		List<HomeCard> list = cardService.doQueryCardEssences(count);
		return new ResponseEntity<>(list, HttpStatus.OK);
	}



	@GetMapping("/card/light/{id}")
	@Timed
	public ResponseEntity<SimpleResult> light(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult();
		Card one = cardService.findOne(id);
		if (one != null) {

			one.setLight(one.getLight() + 1);
			cardService.save(one);
			sr.setSuccess(true);
		}
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}
	@PutMapping("/card/recommend/{id}")
	@Timed
	@Secured(AuthoritiesConstants.ADMIN)
	public ResponseEntity<SimpleResult> recommend(@PathVariable Long id,@ApiParam(required=false) String homeTitle) throws URISyntaxException {
		SimpleResult sr = new SimpleResult(false);
		Card one = cardService.findOne(id);
		if(one==null){
			return new ResponseEntity<>(sr, HttpStatus.NOT_FOUND);
		}
		if (one != null) {
			one.setRecommend(true);
			one.setRecommendTitle(homeTitle);
			cardService.save(one);
			sr.setSuccess(true);
		}
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}
	@PutMapping("/card/cancelhome/{id}")
	@Timed
	@Secured(AuthoritiesConstants.ADMIN)
	public ResponseEntity<SimpleResult> cancelHome(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult(false);
		Card one = cardService.findOne(id);
		if(one==null){
			return new ResponseEntity<>(sr, HttpStatus.NOT_FOUND);
		}
		if (one != null) {
			one.setRecommend(false);
			cardService.save(one);
			sr.setSuccess(true);
		}
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}

	@GetMapping("/card/accusation/{id}")
	@Timed
	public ResponseEntity<SimpleResult> accusation(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult();
		Card one = cardService.findOne(id);
		if (one != null) {
			one.setAccusation((one.getAccusation() == null ? 0 : one.getAccusation()) + 1);
			cardService.save(one);
			sr.setSuccess(true);
		}
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}

	@PutMapping("/applycard/agree/{id}")
	@Timed
	public ResponseEntity<SimpleResult> agreeEssence(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult();
		Card one = cardService.findOne(id);
		if (one == null) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.NOT_FOUND);
		}
		Integer essence = one.getEssence();
		if (essence != 2) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.FORBIDDEN);
		}
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		Long uid = user.getId();
		List<Moderator> moderators = moderatorService.findByUserId(uid);
		boolean canOperate = false;
		for (Moderator m : moderators) {
			if (m.getCategoryId() == one.getCategoryId()) {
				canOperate = true;
				break;
			}
		}
		if (!canOperate) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.FORBIDDEN);
		}
		one.setEssence(3);
		cardService.save(one);
		sr.setSuccess(true);
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}

	@PutMapping("/applycard/deny/{id}")
	@Timed
	public ResponseEntity<SimpleResult> denyEssence(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult();
		Card one = cardService.findOne(id);
		if (one == null) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.NOT_FOUND);
		}
		Integer essence = one.getEssence();
		if (essence != 2) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.FORBIDDEN);
		}
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		Long uid = user.getId();
		List<Moderator> moderators = moderatorService.findByUserId(uid);
		boolean canOperate = false;
		for (Moderator m : moderators) {
			if (m.getCategoryId() == one.getCategoryId()) {
				canOperate = true;
				break;
			}
		}
		if (!canOperate) {
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.FORBIDDEN);
		}
		one.setEssence(1);
		cardService.save(one);
		sr.setSuccess(true);
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}
}
